package com.shuma.user.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shuma.user.common.ErrorCode;
import com.shuma.user.exception.BusinessException;
import com.shuma.user.mapper.UserMapper;
import com.shuma.user.pojo.User;
import com.shuma.user.service.UserService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* @author shanyi
* @description 针对表【user(用户信息表)】的数据库操作Service实现
* @createDate 2024-06-17 16:10:04
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
    implements UserService{

    private static final Logger LOG = LoggerFactory.getLogger(UserServiceImpl.class);

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 盐值，混淆密码
     */
    private static final String SALT = "shanyi";

    @Override
    public User userLogin(String userName,String PassWord) {
        /**
         * 1.首先判断参数是否合法
         * 2.检查用户名和密码是否在表中
         * 3.在的话登录成功，生成token，返回给前端，且把信息放入SaToken
         * **/

        // 1. 校验
        if (StringUtils.isAnyBlank(userName, PassWord)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空");
        }
        //用户名长度不能小于4
        if (userName.length() < 4) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号错误");
        }
        //密码长度不能小于8
        if (PassWord.length() < 8) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码错误");
        }
        //特殊字符检验
        String vailPattern = "[`~!@#$%^&*()+=|{}':;',\\\\[\\\\].<>/?~！@#￥%……&*（）——+|{}【】‘；：”“’。，、？]";
        Matcher matcher = Pattern.compile(vailPattern).matcher(userName);
        if(matcher.find())
        {
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"特殊字符不允许");
        }
        // 2. 加密
        String encryptPassword = DigestUtils.md5DigestAsHex((SALT + PassWord).getBytes());
        // 查询用户是否存在
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", userName);
        queryWrapper.eq("password", encryptPassword);
        User user = userMapper.selectOne(queryWrapper);
        // 用户不存在
        if (user == null) {
            LOG.info("user login failed, userAccount cannot match userPassword");
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户不存在或密码错误");
        }
        //这里用到了一个so-token框架放回token更便捷方便
        // 查到，返回token给前端
        StpUtil.login(user.getUserId());  // 会自动返回
        //脱敏，防止将敏感信息传给前端，我们需要对其进行处理
        User safeuser = getsafeuser(user);
        // 打印当前登录人ID
        LOG.info("当前登录人ID:{}", StpUtil.getLoginId());
        List<User> users = queryUser(StpUtil.getLoginIdAsLong());
        LOG.info("当前用户角色为{}", users.get(0).getRole());
        // 将该角色放入redis中
        redisTemplate.opsForValue().set(StpUtil.getLoginId(), users.get(0).getRole());
        LOG.info("从redis取出当前用户角色为{}", redisTemplate.opsForValue().get(StpUtil.getLoginId()));
        return safeuser;
    }

    public List<User> queryUser(Long id) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        if (id != 0) {
            queryWrapper.eq(User::getUserId, id);
        }
        return userMapper.selectList(queryWrapper);
    }

    @Override
    public String sendCode(String phone) {

        //1.符合则生成验证码
        String code = RandomUtil.randomNumbers(6);
        //将验证码存入redis中
        stringRedisTemplate.opsForValue().set("login:code:"+phone,code,2L, TimeUnit.MINUTES);
        return code;
    }

    @Override
    public Boolean userRegister(String userName, String password, String checkpassword, String phoneNumber,String captcha) {
        if(StringUtils.isAnyBlank(userName,password,checkpassword,captcha))
        {
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"参数为空");
        }
        if(userName.length()<4)
        {
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"用户账号长度小于4");
        }
        if(password.length()<8 || checkpassword.length()<8)
        {
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"密码长度小于8");
        }
        //特殊字符检验
        String vailPattern = "[`~!@#$%^&*()+=|{}':;',\\\\[\\\\].<>/?~！@#￥%……&*（）——+|{}【】‘；：”“’。，、？]";
        Matcher matcher = Pattern.compile(vailPattern).matcher(userName);
        if(matcher.find())
        {
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"特殊字符不允许");
        }

        if(!password.equals(checkpassword))
        {
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"两次密码不相等");
        }
        //从缓存中取出验证码，进行校验
        String cachecode =stringRedisTemplate.opsForValue().get("login:code:"+phoneNumber);
        System.out.println(cachecode);
        if(!cachecode.equals(captcha))
        {
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"验证码不正确");
        }
        //账号不能重复
        QueryWrapper<User> objectQueryWrapper = new QueryWrapper<>();
        objectQueryWrapper.eq("username",userName);
        long count=userMapper.selectCount(objectQueryWrapper);
        if(count>0)
        {
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"账号已存在");
        }
        //手机号不能重复
        objectQueryWrapper = new QueryWrapper<>();
        objectQueryWrapper.eq("phone",phoneNumber);
        count=userMapper.selectCount(objectQueryWrapper);
        if(count>0)
        {
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"手机号已存在");
        }
        //加密 盐值
        final String salt="shanyi";
        String newPassword = DigestUtils.md5DigestAsHex((salt+password).getBytes(StandardCharsets.UTF_8));
        //插入数据
        User user = new User();
        user.setUsername(userName);
        user.setPassword(newPassword);
        user.setPhone(phoneNumber);
        boolean save = this.save(user);
        if (!save) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR,"系统内部异常");
        }
        return save;
    }

    @Override
    public Boolean userForgetPassWord(String userName, String password, String checkpassword, String phoneNumber, String captcha) {
        if(userName.length()<4)
        {
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"用户账号长度小于4");
        }
        if(password.length()<8 || checkpassword.length()<8)
        {
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"密码长度小于8");
        }
        //特殊字符检验
        String vailPattern = "[`~!@#$%^&*()+=|{}':;',\\\\[\\\\].<>/?~！@#￥%……&*（）——+|{}【】‘；：”“’。，、？]";
        Matcher matcher = Pattern.compile(vailPattern).matcher(userName);
        if(matcher.find())
        {
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"特殊字符不允许");
        }

        if(!password.equals(checkpassword))
        {
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"两次密码不相等");
        }
        //从缓存中取出验证码，进行校验
        String cachecode =stringRedisTemplate.opsForValue().get("login:code:"+phoneNumber);
        System.out.println(cachecode);
        if(!cachecode.equals(captcha))
        {
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"验证码不正确");
        }
        //使用updateWrapper 对象构造更新条件
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        // 在 updateWrapper 中设置了两个条件：phone 等于给定的 phoneNumber 和 username 等于给定的 userName。
        updateWrapper.eq("phone",phoneNumber);
        updateWrapper.eq("username",userName);
        //加密 盐值
        final String salt="shanyi";
        String newPassword = DigestUtils.md5DigestAsHex((salt+password).getBytes(StandardCharsets.UTF_8));
        //将新密码保存在数据库
        updateWrapper.set("password",newPassword);
        return this.update(updateWrapper);

    }

    public User getsafeuser(User user1)
    {
        if(user1==null)
        {
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR,"用户未登录");
        }
        User safeuser = new User();
        safeuser.setUserId(user1.getUserId());
        safeuser.setUsername(user1.getUsername());
        safeuser.setAvatar(user1.getAvatar());
        safeuser.setGender(user1.getGender());
        safeuser.setPhone(user1.getPhone());
        safeuser.setRole(user1.getRole());
        safeuser.setEmail(user1.getEmail());
        safeuser.setNickname(user1.getNickname());
        safeuser.setCreatTime(user1.getCreatTime());
        return safeuser;
    }

}




